/*
 * Copyright (c) 2022, IMMORTA Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * - Neither the name of IMMORTA Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef UART_LIN_DRV_H
#define UART_LIN_DRV_H

/*!
 * @file uart_lin_drv.h
 * @brief This file declares lin driver interfaces
 */

/*******Includes***************************************************************/
#include "lin_drv.h"

/*******Definitions************************************************************/

/*******APIs*******************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif

/*!
 * @brief Initializes an instance LIN Hardware Interface for LIN Network,
 *        These two point(linConfig,linState) will be reserved for asynchronously use,
 *        It must be pointed to static or global memory
 *
 * @param[in] instance:  LIN Hardware Interface instance number
 * @param[out] ulinState: Pointer to the LIN Hardware Interface driver state structure
 * @param[in] ulinConfig: User configuration structure of type #lin_config_t
 * @return operation status:
 *         - ERR_SUCCESS : Operation was successful
 *         - ERR_ERROR   : Operation failed due to semaphores initialize error
 */
errcode_t UART_LIN_Init(uint32_t instance,
                        lin_state_t* ulinState,
                        lin_config_t* ulinConfig);

/*!
 * @brief Shuts down the LIN Hardware Interface by disabling interrupts and transmitter/receiver
 *
 * @param[in] instance: LIN Hardware Interface instance number
 * @return None
 */
void UART_LIN_Deinit(uint32_t instance);

/*!
 * @brief Initializes a configuration structure received from the application with default values
 *
 * @param[in] isMaster:   Node function:
                - true if node is MASTER
                - false if node is SLAVE
 * @param[out] ulinConfig: the default configuration
 * @return None
 */
void UART_LIN_GetDefaultConfig(bool isMaster,
                               lin_config_t* ulinConfig);

/*!
 * @brief Installs callback function that is used for LIN_IRQHandlerProcess
 *
 * @note  After a callback is installed, it bypasses part of the LIN Hardware Interface IRQHandler logic,
 *        Therefore, the callback needs to handle the indexes of txBuff and txSize
 *
 * @param[in] instance: LIN Hardware Interface instance number
 * @param[in] callback: the LIN receive callback function
 * @param[in] param: Param for user
 * @return None
 */
void UART_LIN_InstallCallback(uint32_t instance,
                              lin_callback_t callback,
                              void* param);

/*!
 * @brief Sends Frame data out through the LIN Hardware Interface using blocking method
 *        This function will calculate the checksum byte and send it with the frame data,
 *        Blocking means that the function does not return until the transmission is complete
 *        This function checks if txSize is in range from 1 to 8, If not it will return ERR_ERROR
 *        This function also returns ERR_ERROR if node's current state is in SLEEP
 *        This function checks if the isBusBusy is false, if not it will return ERR_BUSY
 *        The function does not return until the transmission is complete, If the transmission
 *        is successful, it will return ERR_SUCCESS, If not, it will return ERR_TIMEOUT
 *
 *@Note   if(LIN_GetNodeState(instance) == LIN_NODE_STATE_RECV_HDR_COMPLETED) then call UART_LIN_SendFrameDataBlocking
 *
 * @param[in] instance: LIN Hardware Interface instance number
 * @param[in] txBuff:   source buffer containing 8-bit data chars to send
 * @param[in] txSize:   the number of bytes to send
 * @param[in] timeoutmSec: timeout value in milliseconds
 * @return operation status:
 *         - ERR_SUCCESS : The transmission is successful
 *         - ERR_BUSY    : The transmission is sending
 *         - ERR_TIMEOUT : The transmission isn't successful
 */
errcode_t UART_LIN_SendFrameDataBlocking(uint32_t instance,
                                         const uint8_t* txBuff,
                                         uint8_t txSize,
                                         uint32_t timeoutmSec);

/*!
 * @brief Sends frame data out through the LIN Hardware Interface using non-blocking method
 *        This enables an a-sync method for transmitting data,Non-blocking means
 *        that the function returns immediately
 *        The application has to get the transmit status to know when the transmit is complete
 *        This function will calculate the checksum byte and send it with the frame data,
 *        The function will return immediately after calling this function
 *        If txSize is equal to 0 or greater than 8 or node's current state is in SLEEP
 *        then the function will return ERR_ERROR
 *        If isBusBusy is currently true then the function will return ERR_BUSY
 * @note  If users use LIN_TimeoutService in a timer interrupt handler, then before using this function,
 *        users have to set timeout counter to an appropriate value by using
 *        LIN_SetTimeoutCounter(instance, timeoutVal), The timeout value should be big enough to
 *        complete the transmission
 *        Timeout in real time is (timeoutVal) * (time period that LIN_TimeoutService is called),
 *        For example, if LIN_TimeoutService is called in an timer interrupt with period of 500us,
 *        then timeout in real time is timeoutValue * 500us
 * @param[in] instance: LIN Hardware Interface instance number
 * @param[in] txBuff:   source buffer containing 8-bit data chars to send
 * @param[in] txSize:   the number of bytes to send
 * @return operation status:
 *         - ERR_SUCCESS : The transmission is successful
 *         - ERR_BUSY    : Operation failed due to isBusBusy is currently true
 *         - ERR_ERROR   : Operation failed due to txSize is equal to 0 or greater than 8
 *                            or node's current state is in SLEEP
 */
errcode_t UART_LIN_SendFrameData(uint32_t instance,
                                 const uint8_t* txBuff,
                                 uint8_t txSize);

/*!
 * @brief Get status of an on-going non-blocking transmission
 *        While sending frame data using non-blocking method, users can
 *        use this function to get status of that transmission
 *        The bytesRemaining shows number of bytes that still needed to transmit
 *
 * @param[in] instance:        LIN Hardware Interface instance number
 * @param[out] bytesRemaining: Number of bytes still needed to transmit
 * @return operation status:
 *         - ERR_SUCCESS : The transmission is successful
 *         - ERR_BUSY    : The transmission is sending
 *         - ERR_TIMEOUT : Operation failed due to timeout has occurred
 */
errcode_t UART_LIN_GetTransmitStatus(uint32_t instance,
                                     uint8_t* bytesRemaining);

/*!
 * @brief Receives frame data through the LIN Hardware Interface using blocking method
 *        This function receives data from UART module using blocking method,
 *        the function does not return until the receive is complete, The interrupt handler
 *        LIN_IRQHandlerProcess will check the checksum byte:
 *        If the checksum is correct, it will receive the frame data
 *        If the checksum is incorrect, will return ERR_TIMEOUT and data in rxBuff might be wrong
 *        This function also check if rxSize is in range from 1 to 8, If not, it will return ERR_ERROR
 *        This function also returns ERR_ERROR if node's current state is in SLEEP
 *        This function checks if the isBusBusy is false, if not it will return ERR_BUSY
 *
 *@Note   if(LIN_GetNodeState(instance) == LIN_NODE_STATE_RECV_HDR_COMPLETED) then call UART_LIN_RecvFrmDataBlocking
 *
 * @param[in] instance: LIN Hardware Interface instance number
 * @param[out] rxBuff:  buffer containing 8-bit received data
 * @param[in] rxSize:   the number of bytes to receive
 * @param[in] timeoutmSec: timeout value in milliseconds
 * @return operation status:
 *         - ERR_SUCCESS : The receives frame data is successful
 *         - ERR_TIMEOUT : The checksum is incorrect
 *         - ERR_BUSY    : Bus busy flag is true
 *         - ERR_ERROR   : Operation failed due is equal to 0 or greater than 8 or
 *                            node's current state is in SLEEP
 */
errcode_t UART_LIN_RecvFrmDataBlocking(uint32_t instance,
                                       uint8_t* rxBuff,
                                       uint8_t rxSize,
                                       uint32_t timeoutmSec);

/*!
 * @brief Receives frame data through the LIN Hardware Interface using non-blocking method
 *        This function will check the checksum byte. If the checksum is correct, it will
 *        receive it with the frame data, Non-blocking means that the function returns immediately
 *        The application has to get the receive status to know when the reception is complete
 *        The interrupt handler LIN_IRQHandlerProcess will check the checksum byte:
 *        If the checksum is correct, it will receive the frame data
 *        If the checksum is incorrect, will return ERR_TIMEOUT and data in rxBuff might be wrong
 *        This function also check if rxSize is in range from 1 to 8, If not, it will return ERR_ERROR
 *        This function also returns ERR_ERROR if node's current state is in SLEEP
 *        This function checks if the isBusBusy is false, if not it will return ERR_BUSY
 * @note  If users use LIN_TimeoutService in a timer interrupt handler, then before using this function,
 *        users have to set timeout counter to an appropriate value by using
 *        LIN_TimeoutService(instance, timeoutVal), The timeout value should be big enough to
 *        complete the reception
 *        Timeout in real time is (timeoutVal) * (time period that LIN_TimeoutService is called)
 *        For example, if LIN_TimeoutService is called in an timer interrupt with period of 500us,
 *        then timeout in real time is timeoutValue * 500us
 *
 * @param[in] instance: LIN Hardware Interface instance number
 * @param[out] rxBuff:  buffer containing 8-bit received data
 * @param[in] rxSize:   the number of bytes to receive
 * @return operation status:
 *         - ERR_SUCCESS : The receives frame data is successful
 *         - ERR_BUSY    : Bus busy flag is true
 *         - ERR_ERROR   : Operation failed due is equal to 0 or greater than 8 or
 *                         node's current state is in SLEEP
 */
errcode_t UART_LIN_RecvFrmData(uint32_t instance,
                               uint8_t* rxBuff,
                               uint8_t rxSize);

/*!
 * @brief Get status of an on-going non-blocking reception
 *        This function returns whether the data reception is complete
 *        When performing non-blocking transmit, the user can call this function to
 *        ascertain the state of the current receive progress:
 *        in progress (ERR_BUSY) or timeout (ERR_TIMEOUT) or complete (ERR_SUCCESS)
 *        In addition, if the reception is still in progress, the user can obtain the number of bytes
 *        that still needed to receive
 *
 * @param[in] instance:        LIN Hardware Interface instance number
 * @param[out] bytesRemaining: Number of bytes still needed to receive
 * @return operation status:
 *         - ERR_SUCCESS : The reception is complete
 *         - ERR_TIMEOUT : The reception isn't complete
 *         - ERR_BUSY    : The reception is on going
 */
errcode_t UART_LIN_GetReceiveStatus(uint32_t instance,
                                    uint8_t* bytesRemaining);

/*!
 * @brief Aborts an on-going non-blocking transmission/reception
 *        While performing a non-blocking transferring data, users can call this function
 *        to terminate immediately the transferring
 *
 * @param[in] instance: LIN Hardware Interface instance number
 * @return None
 */
void UART_LIN_AbortTransferData(uint32_t instance);

/*!
 * @brief Puts current LIN node to sleep state
 *        This function changes current node state to LIN_NODE_STATE_SLEEP
 *
 * @param[in] instance: LIN Hardware Interface instance number
 * @return None
 */
void UART_LIN_GoToSleepState(uint32_t instance);

/*!
 * @brief Puts current LIN node to Idle state
 *        This function changes current node state to LIN_NODE_STATE_IDLE
 *
 * @param[in] instance: LIN Hardware Interface instance number
 * @return None
 */
void UART_LIN_GotoIdleState(uint32_t instance);

/*!
 * @brief Sends a wakeup signal through the LIN Hardware Interface
 *
 * @param instance: LIN Hardware Interface instance number
 * @return operation status:
 *         - ERR_SUCCESS : Bus busy flag is false
 *         - ERR_BUSY    : Bus busy flag is true
 */
errcode_t UART_LIN_SendWakeupSignal(uint32_t instance);

/*!
 * @brief Get the current LIN node state
 *
 * @param[in] instance: LIN Hardware Interface instance number
 * @return current LIN node state
 */
lin_node_state_t UART_LIN_GetNodeState(uint32_t instance);

/*!
 * @brief Callback function for Timer Interrupt Handler
 *        Users may use (optional, not required) LIN_TimeoutService to check if timeout
 *        has occurred during non-blocking frame data transmission and reception
 *        User may initialize a timer (for example TIMER/RTC) with period of 5 microseconds (recommended)
 *        In timer IRQ handler, call this function
 *
 * @param[in] instance: LIN Hardware Interface instance number
 * @return None
 */
void UART_LIN_TimeoutService(uint32_t instance);

/*!
 * @brief Set Value for Timeout Counter that is used in LIN_TimeoutService
 *
 * @param[in] instance:   LIN Hardware Interface instance number
 * @param[in] timeoutVal: Timeout Value to be set
 * @return None
 */
void UART_LIN_SetTimeoutCounter(uint32_t instance,
                                uint32_t timeoutVal);

/*!
 * @brief Sends frame header out through the LIN Hardware Interface using a non-blocking method
 *        This function sends LIN Break field, sync field then the ID with correct parity
 *        This function checks if the interface is Master, if not, it will return ERR_ERROR
 *        This function checks if id is in range from 0 to 0x3F, if not it will return ERR_ERROR
 *
 * @param[in] instance: LIN Hardware Interface instance number
 * @param[in] id:       Frame Identifier
 * @return operation status:
 *         - ERR_SUCCESS : The transmission is successful
 *         - ERR_BUSY    : Bus busy flag is true
 *         - ERR_ERROR   : The interface isn't Master or id isn't in range from 0 to 0x3F
 *                         or node's current state is in SLEEP
 */
errcode_t UART_LIN_MasterSendHeader(uint32_t instance,
                                    uint8_t id);

/*!
 * @brief Set LIN hardware interrupts to enable or disable
 *
 * @param[in] instance: LIN Hardware Interface instance number
 * @param[in] enable: Enable or disable the LIN interrupt
 *            - true: Enable the LIN interrupt
 *            - false: Disable the LIN interrupt
 * @return None
 */
void LIN_LIN_SetIntEnable(uint32_t instance, bool enable);

/*!
 * @brief Gets the bus external physical state
 *
 * @param[in] instance: LIN Hardware Interface instance number
 * @return Bus error status.
 *       -LIN_BUS_STATE_NORMAL: bus normal
 *       -LIN_BUS_STATE_SHORTED_GND: bus error, shorted to GND
 */
lin_bus_state_t UART_LIN_GetBusPhyState(uint32_t instance);

/*!
 * @brief UART_LIN interrupt handler for RX_TX and Error interrupts
 *
 * @param[in] instance: UART instance number
 * @return None
 */
void UART_LIN_IRQHandlerProcess(uint32_t instance);


#if defined(__cplusplus)
}
#endif

#endif /* UART_LIN_DRV_H */

/*******EOF********************************************************************/
